'use strict';
/**
 * Created by zhouzhongyuan on 2016/1/6.
 */

/************* requirejs.config ***************/
requirejs.config({
  baseUrl: './',
  paths  : {
    jquery            : "vendor/jquery/jquery",
    underscore        : "vendor/underscore/underscore",
    backbone          : "vendor/backbone/backbone",
    backboneValidation: "vendor/backbone/backbone-validation-amd",
    logger            : "app/common/logger",
    text              : "vendor/requirejs/text",
    then              : "vendor/thenjs/then",
    store             : "app/base/service/store",
    notice            : "app/base/service/notice",
    remote            : "app/base/service/remote",
    /********************/
    'jquery.form'     : "vendor/jquery/jquery.form",
    'jquery.ui'       : "vendor/jquery/jquery-ui.min",
    /********************/
    plugins           : "vendor/plugins",
    service           : "app/base/service",
    home              : "app/home"
  },
  shim   : {
    'underscore' : {
      exports: '_'
    },
    'backbone'   : {
      deps   : ['underscore', "jquery"],
      exports: 'Backbone'
    },
    'jquery.ui'  : {
      deps   : ['jquery'],
      exports: 'jquery_ui'
    },
    'jquery.form': {
      deps   : ['jquery'],
      exports: 'jquery_form'
    }
  }
});
requirejs.onError = function (err) {
  throw  err;
};
/************* requirejs.config END***************/

/************* app-main ***************/
var $app;
define("app-main",
  ["backbone", "underscore", "backboneValidation"],
  function (Backbone, _, backboneValidation) {
    $app = new (function (_) {
      this.container = {
        controller: {},
        view      : {},
        model     : {},
        service   : {},
        route     : {}
      };
      var _this      = this;
      var argesFun   = function (args, fn, containerName, define) {
        if (_.isString(args)) {
          if (_this.container[containerName].hasOwnProperty(args)) {
            _.isFunction(fn) && fn(_this.container[containerName][args]);
          } else {
            require([args], function (defineFn) {
              _this.container[containerName][args] = defineFn;
              fn(defineFn);
            })
          }
          return;
        }
        if (_.isArray(args)) {
          var argsFirst = _.first(args);
          if (_.isArray(argsFirst)) {
            var local   = {};
            var unlocal = [];
            _.each(argsFirst, function (value, index) {
              if (_this.container[containerName].hasOwnProperty(value)) {
                local[index] = (_this.container[containerName][value]);
              } else {
                local[value] = index;
                unlocal.push(value);
              }
            });
            if (unlocal.length == 0) {
              fn.apply(fn, _.values(local));
            } else {
              require(unlocal, function () {
                var _arguments = arguments;
                _.each(unlocal, function (value, index) {
                  if (local.hasOwnProperty(value)) {
                    local[local[value]]                   = _arguments[index];
                    _this.container[containerName][value] = _arguments[index];
                  }
                  delete local[value];
                });
                fn.apply(fn, _.values(local));
              })
            }
            return;
          }
          define(args, fn);
          return;
        }
        if (_.isFunction(args)) {
          fn           = args;
          var fnstring = fn.toString();
          var fnargs   = fnstring.substring(fnstring.indexOf('(') + 1, fnstring.indexOf(')')).replace(/\s/g, "").split(',');
          !_.isEmpty(fnargs) ? define(fnargs, fn) : define([], fn);
        }
      };
      return {
        controller: function (args, fn) {
          argesFun(args, fn, "controller", function (args, fn) {
            var _args = [];
            _.each(args, function (value) {
              value == "$" ? value = "jquery" : "";
              value == "_" ? value = "underscore" : "";
              _args.push(value);
            });
            define(_args, fn);
          });
        },
        view      : function (args, fn) {
          argesFun(args, fn, "view", function (args, fn) {
            define(args, function () {
              return Backbone.View.extend(fn.apply(fn, arguments));
            });
          });
        },
        model     : function (args, fn) {
          argesFun(args, fn, "model", function (args, fn) {
            var _args = [];
            _.each(args, function (value) {
              value == "$" ? value = "jquery" : "";
              value == "_" ? value = "underscore" : "";
              _args.push(value);
            });
            define(_args, function () {
              return Backbone.Model.extend(fn.apply(fn, arguments));
            });
          });
        },
        service   : function (args, fn) {
          argesFun(args, fn, "service", function (args, fn) {
            var _args = [];
            _.each(args, function (value) {
              value == "$" ? value = "jquery" : "";
              value == "_" ? value = "underscore" : "";
              _args.push(value);
            });
            define(_args, fn);
          });
        },
        require   : function (args, fn) {
          var _dep = {
            view : [],
            model: [],
            other: []
          }, app   = this, deps = {};
          _.each(args, function (value) {
            if (value.indexOf("view") != -1) {
              _dep.view.push(value);
            } else if (value.indexOf("model") != -1) {
              _dep.model.push(value);
            } else {
              _dep.other.push(value);
            }
            deps[value] = undefined;
          });

          app.view([_dep.view], function () {
            if (arguments.length > 0) {
              _.each(arguments, function (value, index) {
                deps[_dep.view[index]] = value;
              })
            }
            app.model([_dep.model], function () {
              if (arguments.length > 0) {
                _.each(arguments, function (value, index) {
                  deps[_dep.model[index]] = value;
                })
              }
              require(_dep.other, function () {
                if (arguments.length > 0) {
                  _.each(arguments, function (value, index) {
                    deps[_dep.other[index]] = value;
                  })
                }
                fn.apply(fn, _.values(deps));
              })
            })
          })
        },
        container : function () {
          return _this.container;
        },
        route     : function (route, name) {
          if (route == undefined) {
            return _this.container.route.default;
          }
          if (_.isString(route)) {
            return _this.container.route[route];
          }
          if (_.isObject(route)) {
            if (name != undefined) {
              _this.container.route[name] = route;
            } else {
              _this.container.route.default = route;
            }
            return route;
          }
        },
        $scope    : {
          $controller: {}
        }
      };
    })(_);

    var Route = Backbone.Router.extend({
      routes    : {
        ":a"      : "action",
        ":c/:a"   : "controller",
        ":m/:c/:a": "modules"
      },
      initialize: function () {
        window.location.hash == "" && this.modules("home", "index", "index");
      },

      action: function (a) {
        this.modules("home", a, "index");
      },

      controller: function (c, a) {
        this.modules("home", c, a);
      },
      modules   : function (m, c, a) {
        var controllerName = "app/" + m + "/controller/" + c;
        var hasParams      = a.indexOf("!");
        var params         = {};
        if (hasParams != -1) {
          var _action = a.substr(0, hasParams);
          var _params = a.substr(hasParams).split("!");
          _.each(_params, function (value) {
            if (value != "") {
              var _split = value.indexOf("=");
              if (_split != -1) {
                params[value.substr(0, _split)] = value.substr(_split + 1);
              }
            }
          });

          a = _action;
        }
        $app.controller(controllerName, function (controller) {
          if (controller.hasOwnProperty(a)) {
            controller[a](params);
            $app.$scope.$controller = {};
          } else {
            console.log("404");
          }
        });
      },
      to        : function (args) {
        if (_.isArray(args)) {
          var route = _.first(args);
          _.each(_.last(args), function (value, index) {
            route = route + "!" + index + "=" + value;
          });
          return route;
        }
      },
      nav       : function (url, replace, trigger) {
        var options = undefined;
        if (replace != undefined || trigger != undefined) {
          options = {trigger: trigger, replace: replace};
        }
        options == undefined ? this.navigate(url, {trigger: true}) : this.navigate(url, options);
      }
    });

    _.extend(Backbone.Model.prototype, backboneValidation.mixin);

    return {
      init: function () {
        $app.route(new Route());
        Backbone.history.start();
      }
    };
  }
);
/************* app-main END***************/

/************* app start***************/
require(["app-main"], function (app) {
  app.init();
});